package com.yc.encrypt.cdd;

import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.SecureUtil;
import org.apache.commons.lang3.StringUtils;

import java.util.HashSet;
import java.util.Set;

/**
 * author: yc
 * description: 兑换码
 * date: 2022/2/7 10:57
 * 原理示意图：https://gitmind.cn/app/flowchart/6455721490
 */
public class YzmUtil {

    /**
     * 生成兑换码
     * @param type
     * @return
     */
    public static String create(int type) {
        if (type < 1 || type > 4095) {
            throw new RuntimeException("类型不在可使用范围内");
        }
        String res = typeCode(type) + mainCode();
        return encCode(res) + res;
    }

    /**
     * 校验验证码
     * @param yzm
     * @return true 校验成功   false 校验失败
     */
    private static boolean check(String yzm) {
        if (StringUtils.isEmpty(yzm) || yzm.length() != 16) {
            return false;
        }
        String enc = yzm.substring(0, 3);
        String code = yzm.substring(3);
        if (!encCode(code).equals(enc)) {
            return false;
        }
        return true;
    }

    //第一部分：校验码：拼接两段编码，然后md5，取后3位
    private static String encCode(String code) {
        return SecureUtil.md5(code + code).substring(29);
    }

    //第二部分：类型区分（可阅读部分）：转成3位十六进制
    private static String typeCode(int type) {
        return HexUtil.toUnicodeHex(type).substring(3);
    }

    //第三部分：主要编码：uuid的后10位
    private static String mainCode() {
        return java.util.UUID.randomUUID().toString().replace("-", "").substring(22);
    }

    public static void main(String[] args) {
        //1000000个兑换码
        int num = 1000000;

        //生成
        long t1 = System.currentTimeMillis();
        Set<String> s = new HashSet<>();
        for (int i=0; i<num; i++) {
            String code = create(1);
            s.add(code);
        }
        long t2 = System.currentTimeMillis();
        System.out.println("生成" + num + "个兑换码，用时：" + (t2-t1) + "毫秒");
        System.out.println("重复率：" + (num-s.size())/num);

        //解码
        for (String item : s) {
            check(item);
        }
        System.out.println("解码" + num + "个兑换码，用时：" + (System.currentTimeMillis()-t2) + "毫秒");
    }
}
